package com.xique.park.service.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xique.common.core.domain.R;
import com.xique.common.core.enums.MngTypeEnum;
import com.xique.common.core.web.domain.PageResult;
import com.xique.park.bean.domain.ParkStatisticsInOut;
import com.xique.park.bean.dto.ParkInDto;
import com.xique.park.bean.dto.ParkOutDto;
import com.xique.park.bean.vo.web.statistics.ParkStatisticsInOutVo;
import com.xique.park.mapper.ParkStatisticsInOutMapper;
import com.xique.park.service.service.IParkInService;
import com.xique.park.service.service.IParkOutService;
import com.xique.park.service.service.IParkStatisticsInOutService;
import com.xique.system.api.RemoteSystemProjectService;
import com.xique.system.api.dto.SystemProjectDTO;
import com.xique.system.api.request.RemoteSystemProjectAllListRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;

/**
 * 车次统计报表功能服务实现
 *
 * @author xique
 */
@RequiredArgsConstructor
@Service
public class ParkStatisticsInOutServiceImpl extends ServiceImpl<ParkStatisticsInOutMapper, ParkStatisticsInOut> implements IParkStatisticsInOutService {

    private final RemoteSystemProjectService remoteSystemProjectService;

    private final IParkInService parkInService;

    private final IParkOutService parkOutService;

    private final ParkStatisticsInOutMapper parkStatisticsInOutMapper;

    private static final String TIME_ZERO = "00:00:00";

    /**
     * 内部车管理类型 - 1：月卡类、2：登记临停类、10：免费类
     */
    private static final List<String> INNER_TYPE_LIST = Arrays.asList(MngTypeEnum.MONTHLY_CARD.getType(), MngTypeEnum.REGISTER_TEMPORARY.getType(), MngTypeEnum.FREE.getType());

    /**
     * 临时车管理类型 - 3：邀请访客类、4：会员临停类、5：临停类
     */
    private static final List<String> TEMPORARY_TYPE_LIST = Arrays.asList(MngTypeEnum.INVITE_VISITORS.getType(), MngTypeEnum.MEMBER_TEMPORARY.getType(), MngTypeEnum.TEMPORARY.getType());

    @Override
    public void initParkStatisticsInOut(Long parkId) {
        if (parkId == null) {
            // 获取所有项目列表
            R<List<SystemProjectDTO>> systemProjectListResult = remoteSystemProjectService.getProjectList(new RemoteSystemProjectAllListRequest());
            List<SystemProjectDTO> systemProjectList = systemProjectListResult.getData();
            // 初始化所有项目
            systemProjectList.forEach(systemProjectDTO -> {
                Long projectId = systemProjectDTO.getId();
                initProjectStatisticsInOut(projectId);
            });
        } else {
            // 初始化当前项目
            initProjectStatisticsInOut(parkId);
        }
    }

    private void initProjectStatisticsInOut(Long parkId) {
        Map<String, ParkStatisticsInOut> parkStatisticsInOutMap = new HashMap<>(16);

        // 临时车进场车次数量
        List<ParkInDto> tempStatisticsInList = parkInService.statisticsByMngTypeAndDay(parkId, TEMPORARY_TYPE_LIST);
        tempStatisticsInList.forEach(parkInDto -> {
            String statisticalTime = parkInDto.getStatisticalTime();
            long inTemporaryStopCar = parkInDto.getInSum();

            ParkStatisticsInOut parkStatisticsInOut = parkStatisticsInOutMap.get(statisticalTime);
            if (parkStatisticsInOut == null) {
                parkStatisticsInOut = new ParkStatisticsInOut();
            }
            parkStatisticsInOut.setInTemporaryStopCar(inTemporaryStopCar);
            parkStatisticsInOut.setStatisticalTime(DateUtil.parseLocalDateTime(statisticalTime + " " + TIME_ZERO));

            parkStatisticsInOutMap.put(statisticalTime, parkStatisticsInOut);
        });

        // 内部车进场车次数量
        List<ParkInDto> innerStatisticsInList = parkInService.statisticsByMngTypeAndDay(parkId, INNER_TYPE_LIST);
        innerStatisticsInList.forEach(parkInDto -> {
            String statisticalTime = parkInDto.getStatisticalTime();
            long inInteriorCar = parkInDto.getInSum();

            ParkStatisticsInOut parkStatisticsInOut = parkStatisticsInOutMap.get(statisticalTime);
            if (parkStatisticsInOut == null) {
                parkStatisticsInOut = new ParkStatisticsInOut();
            }
            parkStatisticsInOut.setInInteriorCar(inInteriorCar);
            parkStatisticsInOut.setStatisticalTime(DateUtil.parseLocalDateTime(statisticalTime + " " + TIME_ZERO));

            parkStatisticsInOutMap.put(statisticalTime, parkStatisticsInOut);
        });

        // 临时车出场车次数量
        List<ParkOutDto> tempStatisticsOutList = parkOutService.statisticsByMngTypeAndDay(parkId, TEMPORARY_TYPE_LIST);
        tempStatisticsOutList.forEach(parkOutDto -> {
            String statisticalTime = parkOutDto.getStatisticalTime();
            long outTemporaryStopCar = parkOutDto.getOutSum();

            ParkStatisticsInOut parkStatisticsInOut = parkStatisticsInOutMap.get(statisticalTime);
            if (parkStatisticsInOut == null) {
                parkStatisticsInOut = new ParkStatisticsInOut();
            }
            parkStatisticsInOut.setOutTemporaryStopCar(outTemporaryStopCar);
            parkStatisticsInOut.setStatisticalTime(DateUtil.parseLocalDateTime(statisticalTime + " " + TIME_ZERO));

            parkStatisticsInOutMap.put(statisticalTime, parkStatisticsInOut);
        });

        // 内部车出场车次数量
        List<ParkOutDto> innerStatisticsOut = parkOutService.statisticsByMngTypeAndDay(parkId, INNER_TYPE_LIST);
        innerStatisticsOut.forEach(parkOutDto -> {
            String statisticalTime = parkOutDto.getStatisticalTime();
            long outInteriorCar = parkOutDto.getOutSum();

            ParkStatisticsInOut parkStatisticsInOut = parkStatisticsInOutMap.get(statisticalTime);
            if (parkStatisticsInOut == null) {
                parkStatisticsInOut = new ParkStatisticsInOut();
            }
            parkStatisticsInOut.setOutInteriorCar(outInteriorCar);
            parkStatisticsInOut.setStatisticalTime(DateUtil.parseLocalDateTime(statisticalTime + " " + TIME_ZERO));

            parkStatisticsInOutMap.put(statisticalTime, parkStatisticsInOut);
        });

        List<ParkStatisticsInOut> parkStatisticsInOutList = new ArrayList<>();
        parkStatisticsInOutMap.values().forEach(parkStatisticsInOut -> {
            parkStatisticsInOut.setInSum(parkStatisticsInOut.getInTemporaryStopCar() + parkStatisticsInOut.getInInteriorCar());
            parkStatisticsInOut.setOutSum(parkStatisticsInOut.getOutTemporaryStopCar() + parkStatisticsInOut.getOutInteriorCar());
            parkStatisticsInOut.setParkId(parkId);
            parkStatisticsInOut.setCreateTime(LocalDateTime.now());
            parkStatisticsInOutList.add(parkStatisticsInOut);
        });

        // 删除之前的记录
        deleteByParkId(parkId);

        // 新增记录
        addBatch(parkStatisticsInOutList);
    }

    private void addBatch(List<ParkStatisticsInOut> parkStatisticsInOutList) {
        saveBatch(parkStatisticsInOutList);
    }

    private void deleteByParkId(Long parkId) {
        LambdaQueryWrapper<ParkStatisticsInOut> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(ParkStatisticsInOut::getParkId, parkId);
        remove(queryWrapper);
    }

    @Override
    public void statisticsInOutByDay(String day) {
        // 获取所有项目列表
        R<List<SystemProjectDTO>> systemProjectListResult = remoteSystemProjectService.getProjectList(new RemoteSystemProjectAllListRequest());
        List<SystemProjectDTO> systemProjectList = systemProjectListResult.getData();
        // 新增每个项目指定日期的车次统计
        systemProjectList.forEach(systemProjectDTO -> {
            Long parkId = systemProjectDTO.getId();
            if (parkId != null && day != null) {
                // 临时车进场车次数量
                long inTemporaryStopCar = parkInService.statisticsByMngTypeAndAppointDay(parkId, day, TEMPORARY_TYPE_LIST);
                // 内部车进场车次数量
                long inInteriorCar = parkInService.statisticsByMngTypeAndAppointDay(parkId, day, INNER_TYPE_LIST);
                // 临时车出场车次数量
                long outTemporaryStopCar = parkOutService.statisticsByMngTypeAndAppointDay(parkId, day, TEMPORARY_TYPE_LIST);
                // 内部车出场车次数量
                long outInteriorCar = parkOutService.statisticsByMngTypeAndAppointDay(parkId, day, INNER_TYPE_LIST);

                ParkStatisticsInOut parkStatisticsInOut = new ParkStatisticsInOut();
                parkStatisticsInOut.setInTemporaryStopCar(inTemporaryStopCar);
                parkStatisticsInOut.setInInteriorCar(inInteriorCar);
                parkStatisticsInOut.setInSum(inTemporaryStopCar + inInteriorCar);
                parkStatisticsInOut.setOutTemporaryStopCar(outTemporaryStopCar);
                parkStatisticsInOut.setOutInteriorCar(outInteriorCar);
                parkStatisticsInOut.setOutSum(outTemporaryStopCar + outInteriorCar);
                parkStatisticsInOut.setParkId(parkId);
                parkStatisticsInOut.setStatisticalTime(DateUtil.parseLocalDateTime(day + " " + TIME_ZERO));
                parkStatisticsInOut.setCreateTime(LocalDateTime.now());

                LambdaQueryWrapper<ParkStatisticsInOut> queryWrapper = Wrappers.lambdaQuery();
                queryWrapper.eq(ParkStatisticsInOut::getParkId, parkId);
                queryWrapper.eq(ParkStatisticsInOut::getStatisticalTime, day);

                saveOrUpdate(parkStatisticsInOut, queryWrapper);
            }
        });
    }

    @Override
    public PageResult getParkStatisticsInOut(Long parkId, Integer type, String startTime, String endTime, Integer pageNum, Integer pageSize) {
        Page<ParkStatisticsInOutVo> page = new Page<>();
        page.setCurrent(pageNum);
        page.setSize(pageSize);

        IPage<ParkStatisticsInOutVo> iPage;

        switch (type) {
            // 按日
            case 1:
                iPage = parkStatisticsInOutMapper.selectPageByDay(page, parkId, startTime, endTime);
                handlePageResult(iPage.getRecords());
                break;
            // 按月
            case 2:
                iPage = parkStatisticsInOutMapper.selectPageByMonth(page, parkId, startTime, endTime);
                handlePageResult(iPage.getRecords());
                break;
            // 按年
            case 3:
                iPage = parkStatisticsInOutMapper.selectPageByYear(page, parkId, startTime, endTime);
                handlePageResult(iPage.getRecords());
                break;
            default:
                throw new IllegalArgumentException("车次统计报表查询类型错误，请联系管理员");
        }

        return PageResult.builder()
                .pageNum(pageNum)
                .pageSize(pageSize)
                .totalPages(iPage.getPages())
                .totalSize(iPage.getTotal())
                .list(iPage.getRecords())
                .build();
    }

    private void handlePageResult(List<ParkStatisticsInOutVo> parkStatisticsInOutVoList) {
        if (CollUtil.isNotEmpty(parkStatisticsInOutVoList)) {
            parkStatisticsInOutVoList.forEach(parkStatisticsInOutVo -> {
                // 统计时间处理
                String statisticalTimeStr = parkStatisticsInOutVo.getStatisticalTimeStr();
                if (StrUtil.isNotBlank(statisticalTimeStr) && statisticalTimeStr.contains(TIME_ZERO)) {
                    statisticalTimeStr = statisticalTimeStr.substring(0, statisticalTimeStr.lastIndexOf(TIME_ZERO));
                    parkStatisticsInOutVo.setStatisticalTimeStr(statisticalTimeStr);
                }
            });
        }
    }

}
